
#include "StdAfx.h"
#include "headers.h"

////////////////////////////////////////////////////////////////////////////////
// CTOR & DTOR /////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

t_var* CScript::m_vars = NULL;
UINT8** CScript::m_commandHeader = NULL;
INT16 CScript::m_numCommands = 0;

CScript::CScript(ResourceInputStream *buf, int size)
{
	// Init data
	m_cursorPos = 0;
	m_scriptLength = 0;
	m_scriptData = NULL;
	m_crtCommandParams = new INT32[MAX_CMD_PARAMS];
	memset(m_crtCommandParams, 0, MAX_CMD_PARAMS * sizeof(INT32));

	// Init timer
	m_clockStartTime = 0;
	m_waitTime = 0;

	// Init keys
	m_labelID = cConstants::LBL_INVALID;

	// Load
	m_scriptLength = size - sizeof(UINT16);
	buf->ReadUInt16(); // Skip num commands
	m_scriptData = new UINT8[m_scriptLength];

	//buf->ReadArray(m_scriptData, m_scriptLength, 1);
	for(int i=0; i<m_scriptLength; i++)
	{
		m_scriptData[i] = buf->ReadUInt8();
	}

	InitCrtCommand();
}

CScript::~CScript()
{
	SAFE_DEL_ARRAY(m_scriptData);
	SAFE_DEL_ARRAY(m_crtCommandParams);
}

CScript* CScript::LoadScript(UINT32 resID)
{
	ResourceInputStream* buf = GAME_INSTANCE->GetResourceInputStream(resID);
	int size = GAME_INSTANCE->GetResourceSize(resID);
	CScript* script = new CScript(buf, size);
	buf->Close();
	return script;
}

void CScript::Init(UINT32 cmd_header_res_id)
{
	ResourceInputStream* buf = GAME_INSTANCE->GetResourceInputStream(cmd_header_res_id);

	m_numCommands = buf->ReadUInt16();
	UINT16 numVars = buf->ReadUInt16();

	// Commands
	m_commandHeader = new UINT8*[m_numCommands];
	for(UINT16 i=0; i<m_numCommands; i++)
	{
		UINT8 len = buf->ReadUInt8();
		UINT8 size = FIRST_PARAM_OFFSET;
		m_commandHeader[i] = new UINT8[len + 2];
		m_commandHeader[i][0] = len; // Num params
		for(UINT8 j=0; j<len; j++)
		{
			m_commandHeader[i][j + 2] = buf->ReadUInt8(); // Size in bytes of each param
			size += m_commandHeader[i][j + 2];
		}
		m_commandHeader[i][1] = size; // Total command size
	}

	// Vars
	m_vars = new t_var[numVars];
	memset(m_vars, 0, numVars * sizeof(t_var));

	buf->Close();
}

void CScript::Destroy()
{
	if(m_commandHeader != NULL)
	{
		for(INT16 i=0; i<m_numCommands; i++)
		{
			SAFE_DEL_ARRAY(m_commandHeader[i]);
		}
		SAFE_DEL_ARRAY(m_commandHeader);
	}

	SAFE_DEL_ARRAY(m_vars);
}

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

//void CScript::Forward(INT16 offset)
//{
//	if(offset == 0) return;
//
//	if(offset > 0)
//	{
//		// Forward
//		while(offset > 0)
//		{
//			m_cursorPos += GetCrtCommandSize();
//			offset--;
//		}
//	}
//	else
//	{
//		// Backward
//		// TODO
//	}
//
//	InitCrtCommand();
//}

// Shorten version
void CScript::Forward(INT16 offset)
{
	m_cursorPos += GetCrtCommandSize();
	InitCrtCommand();
}

void CScript::GotoLabel(UINT8 labelID)
{
	m_cursorPos = 0;
	UINT16 cmd;
	while(true)
	{
		cmd = GetCommand();
		if(cmd == cConstants::CMD_LABEL && labelID == GetParamValue(cConstants::CMDPARAM_LABEL_LABELID))
		{
			InitCrtCommand();
			return;
		}
		m_cursorPos += GetCrtCommandSize();
	}
}

void CScript::GotoElse()
{
	UINT16 cmd;
	while(true)
	{
		cmd = GetCommand();
		if(cmd == cConstants::CMD_ELSE || cmd == cConstants::CMD_ENDIF)
		{
			InitCrtCommand();
			return;
		}
		m_cursorPos += GetCrtCommandSize();
	}
}

void CScript::GotoEndif()
{
	UINT16 cmd;
	while(true)
	{
		cmd = GetCommand();
		if(cmd == cConstants::CMD_ENDIF)
		{
			InitCrtCommand();
			return;
		}
		m_cursorPos += GetCrtCommandSize();
	}
}

bool CScript::IsEnded()
{
	return (m_cursorPos >= m_scriptLength);
}

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

void CScript::InitCrtCommand()
{
	if(IsEnded())
	{
		_DBG("End of script\n");
		return;
	}

	UINT16 cmd = GetCommand();
	UINT8 numParams = GetCommandNumParams(GetCommand());
	for(UINT8 i=0; i<numParams; i++)
	{
		if(cmd == cConstants::CMD_SET_VAR && i == cConstants::CMDPARAM_SET_VAR_ID)
		{
			m_crtCommandParams[i] = GetParam(i);
		}
		else
		{
			m_crtCommandParams[i] = GetParamValue(i);
		}
	}

#ifdef _DEBUG
	_DBG("Next command: %d", cmd);
	for(UINT8 i=0; i<numParams; i++)
	{
		_DBG(" %d", m_crtCommandParams[i]);
	}
	_DBG("\n");
#endif
}

UINT16 CScript::GetCommand()
{
	// Optimized
	//return (UINT16)CUtils::ReadInt(m_scriptData, m_cursorPos, NUM_BYTES_FOR_COMMAND);
	return CUtils::ReadUInt16(m_scriptData, m_cursorPos);
}

UINT16 CScript::GetNextCommand()
{
	INT32 tmp = m_cursorPos;
	m_cursorPos += GetCrtCommandSize();
	UINT16 cmd = GetCommand();
	m_cursorPos = tmp;
	return cmd;
}

INT32 CScript::GetParam(UINT8 index)
{
	UINT16 cmd = GetCommand();
#if ENABLE_CMD_DEFAULT_PARAM
	if(index >= GetCrtCommandNumParams())
	{
		return GetDefaultParam(cmd, index);
	}
#endif
	INT32 tmp = m_cursorPos + FIRST_PARAM_OFFSET;
	for(UINT8 i=0; i<index; i++)
	{
		tmp += GetParamSize(cmd, i);
	}
	return CUtils::ReadInt(m_scriptData, tmp, GetParamSize(cmd, index));
}

INT32 CScript::GetParamValue(UINT8 index)
{
	INT32 val = GetParam(index);
	if(!IsParamVar(index) || (INT16)val <= OP_NEQ)
	{
		return val;
	}
	else
	{
		return m_vars[val];
	}
}

bool CScript::IsParamVar(UINT8 index)
{
	return ((CUtils::ReadInt(m_scriptData, m_cursorPos + NUM_BYTES_FOR_COMMAND, NUM_BYTES_FOR_PARAM_TYPE) & (1 << index)) != 0);
}

UINT8 CScript::GetCrtCommandSize()
{
#if ENABLE_CMD_DEFAULT_PARAM
	UINT16 cmd = GetCommand();
	UINT8 numParams = GetCrtCommandNumParams();
	if(numParams == GetCommandNumParams(cmd))
	{
		return GetCommandSize(cmd);
	}
	INT32 tmp = m_cursorPos + FIRST_PARAM_OFFSET;
	for(UINT8 i=0; i<numParams; i++)
	{
		tmp += GetParamSize(cmd, i);
	}
	return (UINT8)(tmp - m_cursorPos);
#else
	return GetCommandSize(GetCommand());
#endif
}

UINT8 CScript::GetCrtCommandNumParams()
{
#if ENABLE_CMD_DEFAULT_PARAM
	return CUtils::ReadUInt8(m_scriptData, m_cursorPos + (NUM_BYTES_FOR_COMMAND + NUM_BYTES_FOR_PARAM_TYPE));
#else
	return GetCommandNumParams(GetCommand());
#endif
}

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

void CScript::SetVar(UINT16 index, t_var val)
{
	m_vars[index] = val;
}

t_var CScript::GetVar(UINT16 index)
{
	return m_vars[index];
}

UINT8 CScript::GetCommandNumParams(UINT16 cmd)
{
	return m_commandHeader[cmd][0];
}

UINT8 CScript::GetCommandSize(UINT16 cmd)
{
	return m_commandHeader[cmd][1];
}

UINT8 CScript::GetParamSize(UINT16 cmd, UINT8 index)
{
	return m_commandHeader[cmd][index + 2];
}

#if ENABLE_CMD_DEFAULT_PARAM
INT32 CScript::GetDefaultParam(UINT16 cmd, UINT8 index)
{
	if(cmd == cConstants::CMD_ADD_ACTOR_FADE)
	{
		if(index == cConstants::CMDPARAM_ADD_ACTOR_FADE_END)	return 255;
		if(index == cConstants::CMDPARAM_ADD_ACTOR_FADE_W)		return cConstants::SCR_W;
		if(index == cConstants::CMDPARAM_ADD_ACTOR_FADE_H)		return cConstants::SCR_H;
	}
	if(cmd == cConstants::CMD_WAIT_ACTORS
		|| (cmd == cConstants::CMD_ADD_ACTOR_CAMERA && index == cConstants::CMDPARAM_ADD_ACTOR_CAMERA_ACTOR)
		|| (cmd == cConstants::CMD_SET_ACTIVE_CAMERA && index == cConstants::CMDPARAM_SET_ACTIVE_CAMERA_ID)
		|| (cmd == cConstants::CMD_SET_ACTIVE_TILESET && index == cConstants::CMDPARAM_SET_ACTIVE_TILESET_ID)
		|| (cmd == cConstants::CMD_REMOVE_ACTOR && index == cConstants::CMDPARAM_REMOVE_ACTOR_ID)
		|| (cmd == cConstants::CMD_ACTIVATE_ACTOR && index == cConstants::CMDPARAM_ACTIVATE_ACTOR_ID)
		|| (cmd == cConstants::CMD_DEACTIVATE_ACTOR && index == cConstants::CMDPARAM_DEACTIVATE_ACTOR_ID)
		|| cmd == cConstants::CMD_REMOVE_STORED_ACTOR)
	{
		return cConstants::ACTSLOT_INVALID;
	}
	if(cmd == cConstants::CMD_ADD_ACTOR_CAMERA)
	{
		if(index == cConstants::CMDPARAM_ADD_ACTOR_CAMERA_MINX) return -32768;
		if(index == cConstants::CMDPARAM_ADD_ACTOR_CAMERA_MINY) return -32768;
		if(index == cConstants::CMDPARAM_ADD_ACTOR_CAMERA_MAXX) return 32767;
		if(index == cConstants::CMDPARAM_ADD_ACTOR_CAMERA_MAXY) return 32767;
	}
	if(cmd == cConstants::CMD_ADD_ACTOR_RECT && index == cConstants::CMDPARAM_ADD_ACTOR_RECT_A)
	{
		return 255;
	}
	if(cmd == cConstants::CMD_ON_TAP_GOTO)
	{
		return cConstants::LBL_INVALID;
	}
	if(cmd == cConstants::CMD_FREE_SFX)
	{
		return 65535;
	}

	return 0;
}
#endif // ENABLE_CMD_DEFAULT_PARAM

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

